#include "AnimationSystem.h"
#include "../Messaging/EventSystem.h"
#include "../headers/Base.h"
#include "../tools/Util.h"
#include <fstream>
using namespace std;
bool operator<(const tAnimationComparer & obj1, const tAnimationComparer & obj2)
{
	if(obj1.nObjectType < obj2.nObjectType)
		return true;
	else if(obj1.nObjectClass < obj2.nObjectClass)
		return true;
	else if(obj1.nAnimationAction < obj2.nAnimationAction)
		return true;
	else if(obj1.nAnimationDirection < obj2.nAnimationDirection)
		return true;

	return false;
	//if(obj1.nAnimationDirection < obj2.nAnimationDirection || obj1.nAnimationType < obj2.nAnimationType || obj1.nObjectType < obj2.nObjectType || obj1.nObjectClass < obj2.nObjectClass;
}

CAnimationSystem * CAnimationSystem::GetInstance()
{
	static CAnimationSystem instance;

	return &instance;
}

void CAnimationSystem::ChangeAnimation(int nType, int nClass, int nAction, bool bIsEnemy, int nDirection, CAnimation *pAnimation)
{
	//tAnimationComparer comp;
	//comp.nAnimationDirection = nDirection;
	//comp.nAnimationType = nAction;
	//comp.nObjectType = nType;
	//comp.nObjectClass = nClass;

	int key = nType | nClass | nAction | nDirection | (bIsEnemy ? 1 << 31 : 0);
	tAnimation * anim = NULL;
	for(map<int, tAnimation>::iterator itt = m_Animations.begin(); itt != m_Animations.end(); itt++)
	{
		if((*itt).first == key)
		{
			anim = &m_Animations[key];
			break;
		}
	}

	if(anim != NULL)
	{
		if(pAnimation != NULL)
		{
			if(pAnimation->GetAnimation() != NULL)
				if(anim->nAnimationAction != pAnimation->GetAnimation()->nAnimationAction)
					pAnimation->Reset();
		}
		pAnimation->SetAnimation(anim);
		pAnimation->SetTotalFrames((int)anim->vFrames.size());
	}
	else
	{
		COUT("Animation not found.  Type" << nType << " Class " << nClass << " Action " << nAction << " nDirection " << nDirection);
	}
}

void CAnimationSystem::InitSystem(const char * szFilePath)
{

	ifstream stream(szFilePath, ios_base::binary);

	if(stream.is_open())
	{
		int numCharacters;
		int numAnimations;
		int tempNum;

		char resource[] = "resource/graphics/";

		//stream.read((char*)&numAnimations, sizeof(int));
		stream.read((char*)&numCharacters, sizeof(int));

		for(int c = 0; c < numCharacters; c++)
		{
			stream.read((char*)&numAnimations, sizeof(int));
			try
			{
				for(int i = 0; i < numAnimations; i++)
				{
					tAnimation anim;

					stream.read((char*)&tempNum, sizeof(int));							//Anim Name Length
					stream.read((char*)&anim.animationName, sizeof(char) * tempNum);	//Anim Name
					if(tempNum > 60)
						throw "Animation Name too long";
					anim.animationName[tempNum] = '\0';
					stream.read((char*)&tempNum, sizeof(int));							//File Path Length
					char path[MAX_PATH];
					char p[MAX_PATH];
					stream.read((char*)path, sizeof(char) * tempNum);
					if(tempNum >= MAX_PATH)
						throw "texture path too long";
					path[tempNum] = '\0';//File Path
					p[0] = '\0';
					strcat_s(p, resource);
					strcat_s(p, path);
					anim.nImageID = CTextureManager::GetInstance()->LoadTexture(p);
					stream.read((char*)&tempNum, sizeof(int));							//Speed
					anim.fBaseSpeed = 1.0f / (float)tempNum;
					
					stream.read((char*)&tempNum, sizeof(int));							//Action
					anim.nAnimationAction = tempNum;
					stream.read((char*)&anim.nAnimationDirection, sizeof(int));			//Direction
					stream.read((char*)&anim.nObjectType, sizeof(int));					//Object Type
					stream.read((char*)&anim.nObjectClass, sizeof(int));				//Object class
					stream.read((char*)&anim.hasEvent, sizeof(bool));					//Has event
					stream.read((char*)&anim.eventFrame, sizeof(int));					//Event frame
					stream.read((char*)&tempNum, sizeof(int));
					stream.read((char*)&anim.szEventName, sizeof(char) * tempNum);
					anim.szEventName[tempNum] = '\0';

					stream.read((char*)&tempNum, sizeof(int));							//trigger X
					anim.vTrigger.fX = (float)tempNum;
					stream.read((char*)&tempNum, sizeof(int));							//trigger Y
					anim.vTrigger.fY = (float)tempNum;
					stream.read((char*)&anim.isEnemy, sizeof(bool));

					//Number of frames
					int numFrames;
					stream.read((char*)&numFrames, sizeof(int));

					//Go through each frame
					for(int i = 0; i < numFrames; i++)
					{
						tFrame frame;
						RECT rect;
						stream.read((char*)&rect.left, sizeof(int));					//Draw Top
						stream.read((char*)&rect.top, sizeof(int));						//Draw Left
						stream.read((char*)&rect.right, sizeof(int));					//Draw Bottom
						stream.read((char*)&rect.bottom, sizeof(int));					//Draw Right
						stream.read((char*)&tempNum, sizeof(int));						//Anchor X
						frame.vAnchor.fX = (float)tempNum;
						stream.read((char*)&tempNum, sizeof(int));						//Anchor Y
						frame.vAnchor.fY = (float)tempNum;

						frame.rect = rect;
						//Add frame to list of frames
						anim.vFrames.push_back(frame);
					}
					if(anim.nObjectType == OBJ_SPIRE)
						m_Animations[anim.nObjectType] = anim;
					else
						m_Animations[anim.nAnimationDirection | anim.nAnimationAction | anim.nObjectClass | anim.nObjectType | (anim.isEnemy ? 1 << 31 : 0)] = anim;
				}

				
			}
			catch(char * e)
			{
				
				ofstream output("error.log");
				output << e;
				output.close();
				COUT("Error loading animations " << e);
			}
			catch(std::exception& e)
			{
				ofstream output("error.log");
				output << e.what();
				output.close();
				COUT("Error loading animations" << e.what());
			}
		}
		stream.close();
		
	}
	else
	{
		COUT("Could not find resource for Animation System: " << szFilePath);
	}
	tFrame frame;
	//create temp player animation
	tAnimation animation;
	//animation.fBaseSpeed = 1.0f;
	//animation.nAnimationDirection = East;
	//animation.nAnimationAction = Walk;
	//animation.nObjectClass = Melee;
	//animation.nImageID = CTextureManager::GetInstance()->LoadTexture("resource/graphics/Player_Melee_Transparent.png");
	//animation.nObjectType = OBJ_PLAYER;
	//RECT rect1 = {2112, 0, 2112 + 96, 96};
	//RECT rect2 = {2209, 0, 2209 + 96, 96};
	//RECT rect3 = {2304, 0, 2304 + 96, 96};
	//frame.rect = rect1;
	//animation.vFrames.push_back(frame);
	//frame.rect = rect2;
	//animation.vFrames.push_back(frame);
	//frame.rect = rect3;
	//animation.vFrames.push_back(frame);

	//tAnimationComparer comp;
	//comp.nAnimationDirection = animation.nAnimationDirection;
	//comp.nAnimationAction = animation.nAnimationAction;
	//comp.nObjectType = animation.nObjectType;
	//comp.nObjectClass = animation.nObjectClass;

	//m_Animations[comp.nAnimationDirection | comp.nAnimationAction | comp.nObjectClass | comp.nObjectType] = animation;


	//create temp npc animation
	/*animation.vFrames.clear();
	animation.fBaseSpeed = 1.0f;
	animation.nAnimationDirection = West;
	animation.nAnimationAction = Walk;
	animation.nObjectClass = Melee;
	animation.nImageID = CTextureManager::GetInstance()->LoadTexture("resource/graphics/Enemy_Caster_Transparent.png");
	animation.nObjectType = OBJ_NPC;
	RECT rect4 = {0, 672, 96, 672 + 96};
	RECT rect5 = {96, 672, 96 + 96, 672 + 96};
	RECT rect6 = {96 + 96, 672, 96 * 3, 672 + 96};

	frame.rect = rect4;
	frame.vAnchor.fY = 0.0f;
	frame.vAnchor.fX = 0.0f;
	animation.vFrames.push_back(frame);
	frame.rect = rect5;
	animation.vFrames.push_back(frame);
	frame.rect = rect6;
	animation.vFrames.push_back(frame);

	comp.nAnimationDirection = animation.nAnimationDirection;
	comp.nAnimationAction = animation.nAnimationAction;
	comp.nObjectType = animation.nObjectType;
	comp.nObjectClass = animation.nObjectClass;

	m_Animations[comp.nAnimationDirection | comp.nAnimationAction | comp.nObjectClass | comp.nObjectType] = animation;*/


	//Portal
	animation.vFrames.clear();
	animation.fBaseSpeed = 1.0f;
	animation.nAnimationDirection = 0;
	animation.nAnimationAction = Open;
	animation.nObjectClass = 0;
	animation.nImageID = CTextureManager::GetInstance()->LoadTexture("resource/graphics/Portal.png");
	animation.nObjectType = OBJ_PORTAL;
	RECT rect7 = {0, 0, 166, 166};
	RECT rect8 = {166, 0, 166+166, 166};
	frame.rect = rect7;
	animation.vFrames.push_back(frame);
	frame.rect = rect8;
	animation.vFrames.push_back(frame);

	m_Animations[animation.nAnimationAction | animation.nObjectType] = animation;
}

CAnimation::CAnimation()
{
	m_nCurrentFrame = 0;
	m_nTotalFrames = 0;
	m_fFrameCounter = 0.0f;
	m_fSpeedModifier = 1.0f;
	m_tAnimation = NULL;
	m_bPlaying = true;
}

void CAnimationSystem::Shutdown()
{
	for(map<int, tAnimation>::iterator itt = m_Animations.begin(); itt != m_Animations.end(); itt++)
	{
		CTextureManager::GetInstance()->UnloadTexture((*itt).second.nImageID);
		(*itt).second.vFrames.clear();
	}

	m_Animations.clear();
}

void CAnimation::Play()
{
	m_bPlaying = true;
}

void CAnimation::Reset()
{
	m_nCurrentFrame = 0;
}

void CAnimation::Stop()
{
	m_bPlaying = false;
}
void CAnimation::AdjustSpeed(float mod)
{
	m_fSpeedModifier = mod;
}

void CAnimation::Update(float dt)
{
	if(m_bPlaying && m_tAnimation)
	{
		m_fFrameCounter += dt;

		if(m_fFrameCounter >= m_tAnimation->fBaseSpeed  * m_fSpeedModifier)
		{
			m_nCurrentFrame++;
			if(m_nCurrentFrame > m_nTotalFrames - 1)
				m_nCurrentFrame = 0;
			if(m_nCurrentFrame == GetEventFrame())
			{
				CEventSystem::GetInstance()->SendEvent(m_tAnimation->szEventName);
			}
			m_fFrameCounter = 0.0f;
		}
	}
}

vector2D CAnimation::GetTriggerPoint()
{
	if(m_tAnimation)
		return m_tAnimation->vTrigger;
	else
		return vector2D();
}
